﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using agvcontroller.Common;
using agvcontroller.Log;

namespace agvcsimulator.Driver
{
    public delegate void deleTerminalSocketSimOnConnect(object sender, enumConnect connect);
    public delegate void deleTerminalSendMsg(object sender, string msg);
    public delegate void deleTerminalRCVMsg(object sender, string msg);
    public delegate void deleTerminalOnInput(object sender, List<bool> input);
    public delegate void deleTerminalOnOutput(object sender, List<bool> output);
    public delegate void deleTerminalRequestIO(object sender);

    public class CTerminalSimSocketDriver
    {
        public event deleTerminalSocketSimOnConnect onConnect;
        public event deleTerminalOnOutput OnOutput;
        public event deleTerminalSendMsg OnSendMsg;
        public event deleTerminalRCVMsg OnRcvMsg;
        public event deleTerminalRequestIO OnReqIO;

        Logger Log;

        Thread thrdClient;
        Socket Client;
        IPAddress ServerIP;
        IPEndPoint ServerEndPoint;
        int Port;

        public string Name;

        public bool Connected;

        public CTerminalSimSocketDriver(IPAddress serverip, int port)
        {
            Log = new Logger(string.Format("SimSocketDirver_{0}", port));
            ServerIP = serverip;
            Port = port;
            Name = string.Format("SimSocketDirver_{0}", port);

            ServerEndPoint = new IPEndPoint(ServerIP, Port);
            Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            thrdClient = new Thread(new ThreadStart(ClientProc));

            Log.Info(string.Format("Create Socket Driver (Server IP : {0} , Port : {1})", ServerIP.ToString(), Port));
        }

        public int Connect()
        {
            try
            {
                if (Client.Connected) return 0;

                Client.Connect(ServerIP, Port);

                if (onConnect != null)
                    onConnect(this, enumConnect.CONNECTION);

                thrdClient.Start();

                Connected = true;

                if (onConnect != null)
                    onConnect(this, enumConnect.CONNECTION);

                Log.Info(string.Format("Connect Socket(Server IP : {0} , Port : {1})", ServerIP.ToString(), Port));
            }
            catch (SocketException ex)
            {
                Log.Info(string.Format("Failure Connect Socket(Server IP : {0} , Port : {1})", ServerIP.ToString(), Port));

                return -1;
            }

            return 0;
        }

        public int Close()
        {
            thrdClient.Abort();

            Client.Close();

            if (onConnect != null)
                onConnect(this, enumConnect.DISCONNECTION);

            Connected = false;
            if (onConnect != null)
                onConnect(this, enumConnect.DISCONNECTION);

            Log.Info(string.Format("Closed Socket({0})", Port));

            return CReturnCode.SUCCESS;
        }

        public void Send(string msg)
        {
            if (Client.Connected)
                Client.Send(Encoding.ASCII.GetBytes(msg));

            if (OnSendMsg != null)
                OnSendMsg(this, msg);

            Log.Info(string.Format("Send Message({0}) : {1}", Port, msg));
        }

        public void ClientProc()
        {
            while (true)
            {
                byte[] buffer = new byte[1024];

                int length = Client.Receive(buffer);

                if (length == 0)
                {
                    Connected = false;
                }
                else
                {
                    string msg = Encoding.ASCII.GetString(buffer, 0, buffer.Length);

                    MessageParsing(msg);

                    if (OnRcvMsg != null)
                    {
                        OnRcvMsg(this, msg);

                        Log.Info(string.Format("Receive Message : {0}", msg));
                    }
                }

                Thread.Sleep(100);
            }
        }

        public void MessageParsing(string msg)
        {
            string[] strmsg = msg.Split(':');
            List<bool> IO = new List<bool>();
            switch (strmsg[0])
            {
                case "REQUEST_IO":
                    IO  = GetOutput(strmsg[1]);

                    if (OnReqIO != null)
                        OnReqIO(this);
                    break;
                case "OUTPUT":
                    IO = GetOutput(strmsg[1]);

                    if (OnOutput != null)
                        OnOutput(this, IO);

                    Send(string.Format("ReceiveMessage:{0}", strmsg[0]));
                    break;
                default:
                    Send(string.Format("Invalid Message : {0}", msg));
                    break;
            }
        }

        List<bool> GetOutput(string msg)
        {
            List<bool> output = new List<bool>();
            string[] strio = msg.Split(',');

            foreach (string io in strio)
            {
                output.Add(Convert.ToBoolean(io));
            }

            return output;
        }
    }
}
